/**
 *
 */
class VisualNode extends Object {
  VisualNode _parent;
  List<VisualNode> _children;
  int _zOrder;

  VisualNode get parent() => _parent;
  Collection<VisualNode> get children() => _children;
  int get zOrder()          => _zOrder;
      set zOrder(int value) {
        if (_zOrder != value) {
          _zOrder = value;
          
          if (_parent != null)
            _parent._onChildZOrderChanged(this);
        }
      }
  
  VisualNode() {
    _parent = null;
    _children = new List<VisualNode>();
    _zOrder = 0;
  }

  void addChild(VisualNode child) {
    if (child == null || child._parent == this)
      return;
    if (child._parent != null)
      child._parent.removeChild(child);
    
    assert(child._parent == null);

    int index = _getIndexByZOrder(child._zOrder);
    if (index == _children.length)
      _children.add(child);
    else
      _children.insertRange(index, 1, child);
  }
  
  bool removeChild(VisualNode child) {
    if (child == null ||
        child._parent != this)
      return false;
    
    int index = indexOf(child);
    assert(index != -1);
    
    _children.removeRange(index, 1);
    child._parent = null;
    
    return true;
  }
  
  void draw(Renderer g) {
    for (final item in _children) {
      item.draw(g);
    }
  }
  
  int indexOf(VisualNode child) {
    for (int i = 1; i < _children.length; i++) {
      if (_children[i] === child) {
        return i;
      }
    }
    
    return -1;
  }
  
  void _onChildZOrderChanged(VisualNode child) {
    int index = indexOf(child);
    assert(index != -1);
    _children.removeRange(index, 1);
    
    index = _getIndexByZOrder(child._zOrder);
    if (index == _children.length)
      _children.add(this);
    else
      _children.insertRange(index, 1, this);
  }
  
  int _getIndexByZOrder(int zOrder) {
    if (_children.length == 0 || zOrder < _children[0].zOrder)
      return 0;
    
    for (int i = 1; i < _children.length; i++) {
      var item = _children[i];
      if (zOrder < item._zOrder) {
        return i;
      }
    }
    
    return _children.length;
  }
}
